/*
 Copyright (c) 2020-2023 Xiamen Yaji Software Co., Ltd.

 https://www.cocos.com/

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights to
 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
 of the Software, and to permit persons to whom the Software is furnished to do so,
 subject to the following conditions:

 The above copyright notice and this permission notice shall be included in
 all copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 THE SOFTWARE.
*/

import {
  _decorator,
  Node,
  find,
  Vec3,
  v3,
  game,
  Collider,
  Enum,
} from "cc";
import { Action } from "../../core/action/action";
import { Save } from "../../util/save";
import { Msg } from "../../util/msg";
import { Singleton } from "../../util/Singleton";
import { UI } from '../../core/ui/ui';
import { Res } from "../../core/res/res";
import { ResCache } from "../../core/res/res-cache";
import { ResPool } from "../../core/res/res-pool";
import { Sound } from "../../core/audio/sound";
import { Bind } from '../../core/bind/bind';

import { Actor } from "../actor/actor";
import { DataLevelInst } from "../data/data-core";
import { utils,UtilNode } from "../../util/util";

declare var window: Window;

const { ccclass, property } = _decorator;

enum PHY_GROUP {
    DEFAULT = 1 << 0,
    PLAYER = 1 << 1,
    OTHER = 1 << 2,
};

export class Level extends Singleton {
  // Action objects are used to execute the current set of actions.
  _action: Action | undefined;

  // Level data object to store static game data.
  _data: { [key: string]: any } = {};

  // Level time.
  _time: number = 0;

  // The state at the beginning of the level.
  _isStart = false;

  // The spawn position of the player's level.
  _spawn_pos = v3(0, 2, 0);

  // The score rate of the level.
  _scoreRate: number = 0;

  // The player's game object.
  _player: Actor | undefined;

  // The root node of all objects at game runtime.
  _objectNode: Node | null | undefined;

  // Current upgrade cards.
  currentCards: Array<{ name: string; info: any }> = new Array(3);

  //道路信息数据
  _roadData: any = {};

  //道路插槽位置数据
  _roadPosArr: any = {};

  //主角当前所在插槽位置数据
  _curOnRoadPos: any = 0;

  //背景节点
  _bgNode: Node | null | undefined;

  //关卡索引
  _levelIndex: number = 0; 


  //积分相关
  _gameScore: number = 0; //当前积分
  //距离
  _gameDistance: number = 0; //当前距离
  //距离
  _hp: number = 0; //当前生命

  //加速节点索引
  _speedUpIndex: number = 0;

  //道具相关
  //定义道具对象
  _kItems = {};
  //生成道具距离
  _kItemsMaxNum = 200;
  //道具单位间隔
  _kItemsNum = 20;
  //单组内道具间隔
  _kItemsOneNum = 5;
  //单组内道具数量
  _kItemsGroupNum = 3;
  //游戏开始某一段距离内不许生成道具
  _kItemsInitLengthNum = 50;
  //道具回收的帧间隔
  _kItemsRcIfmNum = 30;
  //道具回收的帧索引
  _kItemsRcIfmIndex = 0;

  //上 一次 房子道具位置
  _lastHousePos = 0;
  _lastHouse1Pos = 1;
  _houseBewteenNum = 2;
  _lastHouseIndex: number = 0; 
  _lastHouse1Index: number = 0; 

  //上 一次 房子道具位置
  _lastTreePos = 0;
  _lastTree1Pos = 1;
  _treeBewteenNum=1;
  _lastTreeIndex: number = 0; 
  _lastTree1Index: number = 0; 


  //道具生成的概率百分百
  _dangerousNum = 20;
  //生成概率每百米加速度
  _dangerousAddNum = 2;

  _kItemTypes = ["star", "bigStar"]; //道具类型列表
  _kItemDangerousTypes = ["lightning", "stone"]; //道具类型列表
  _kItemPositions = [-3, 0, 3]; //道具位置列表

  //物理配置（分组掩码）
  PHY_GROUP = PHY_GROUP;
  /**
   * Initialize the level object.
   */
  public init(): void {
    window["level"] = this;

    // Get the level data and copy it for storage.
    this._data = Object.assign(ResCache.Instance.getJson("data-level").json);

    // Create an action object to manage the action of the level.
    this._action = new Action("action-level");

    // Find the root node of all objects.
    this._objectNode = find("init")?.getChildByName("objects");

    //尝试获取背景节点
    this._bgNode = find("init")?.getChildByName("objects").getChildByName("game-bg");

    this._bgNode.getChildByName(`bg_${this._levelIndex+1}`).active = true;
    

    // Register external message access function mapping.
    Msg.on("msg_level_start", this.onLevelStart.bind(this));
    Msg.on("level_do", this.do.bind(this));

    //根据配置赋值生命值
    this._hp = this._data.level_hp;

    this.initSomeDataToPool();

  }


  //节点池预加载，json中预设对象数量
  initSomeDataToPool() {
    for (const key in DataLevelInst._data.pool_config) {
      const count = DataLevelInst._data.pool_config[key];
      ResPool.Instance.newPool(key, count);
    }
  }

  /**
   * Executes the function with the name specified by the current object.
   * @param fun Name of the function to be executed.
   */
  public do(fun: string) {
    this[fun]();
  }

  /**
   * This function is used to set the behavior related to the start of the level.
   */
  public onLevelStart() {
    // Set level stop is false.
    DataLevelInst.stop = false;
    this._isStart = true;
    this._player._isDisableStop = false;
    
    this.levelAction("startAction");
  }

  public pause() {
    DataLevelInst.stop = true;
  }

  public resume() {
    DataLevelInst.stop = false;
  }

  /**
   * This method is used to restart the game.
   */
  public onReplay() {
    utils.delay(() => {
      Msg.emit("push", "level");
    }, 2);
  }

  public levelAction(name: string) {
    console.log("levelActionlevelAction");
    this._action!.on(name);
  }

  /**
   * Added level role method.
   * Used to initialize the character game object.
   */

  public addPlayer() {
    // Get a random node from the navigation system.
    console.log("addPlayeraddPlayeraddPlayer");

    // Get the player's prefab object from the resource cache.
    const prefab = ResCache.Instance.getPrefab(this._data.prefab_player);

    // Instantiate player level game object.
    const resPlayer = Res.inst(prefab, this._objectNode!);

    // Get the Actor from the player level game object.
    this._player = resPlayer.getComponent(Actor)!;

    var playerModel = UtilNode.find(this._player.node, "model_node");
    playerModel.getChildByName(`player_${this._levelIndex+1}`).active = true;

    // Detect if this actor exists
    if (this._player === null) {
      throw new Error(`Level add player can not bind Actor Component.`);
    }

    // Set the player tag value of this actor to true.
    this._player.isPlayer = true;

    // Initialize the player object.
    //用data-player.json数据初始化角色数据
    this._player.init("data-player");

    // Update player hp.
    this._player.updateHP();

    //检测主角碰撞
    this.listenCollision(this._player.node);

    //尝试初始化地图
    this.generateItems();

    Msg.emit("camera-watch", this._player?.node);
  }

  public generateItems(){
    console.log("generateItems");
  }
    // //回收房子
    // if(roadData.house1){
    //   ResPool.Instance.push(roadData.house1);
    //   }


  public getHouse() {
    const house = ResPool.Instance.pop("house", Vec3.ZERO);
    return house;
  }




  public update(deltaTime: number): void {
    if (!this._isStart) return;
    if (DataLevelInst.stop) return;

    // this.gameOver();

    this._time += deltaTime;
    this._action!.update(deltaTime);

    

    //主角移动
    // var pos = this._player?.node.getPosition();
    // if (pos) {
    //   var addNum =  this.someTimeAddSpeedFn(this._gameDistance);
    //   var addSpeed= (this._data.speed_init + (this._data.speed_add*((this._gameDistance+addNum)/100)))
    //   addSpeed = (addSpeed>this._data.speed_max?this._data.speed_max:addSpeed)*deltaTime;
    //   pos.z -= addSpeed;
    //   // pos.z -=1;
    //   this._gameDistance = -pos.z;
    //   this._player._logicPos.z = pos.z;

    //   // this._gameScore += (deltaTime);
    //   UI.Instance._map["ui_operation"].refresh();

    //   this.generateItems(pos);

    //   this.moveBg();
    // }

  }

  //加分
  addScore(score: number) {
    this._gameScore += score;
    Sound.on("coin",0.1);
    // UI.Instance.s();
    Save.Instance.set("level_score", this._gameScore);
    UI.Instance._map["ui_operation"].refresh();
  }



  public gameOver() {
    // Set level stop is true.
    DataLevelInst.stop = true;
    this._isStart = false;
    this._player._isDisableStop = true;

    Msg.emit("push","levelEnd");

    Msg.emit("postMsgToParent",{
      score:this._gameScore,
      length:this._gameDistance,
      time:this._time,
    });

  }



 
}
